package logo.sys;

import logo.lang.*;
import logo.utils.*;
import java_cup.runtime.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.Vector;

@SuppressWarnings("serial")
public class LogoApplet extends JApplet 
{
    static final String PROMPT = "Logo> ";
    static final int inputBufferCapacity = 200;
    static final int byteBufferCapacity = 100;
    JTextArea history = new JTextArea(22, 10);
    JTextArea text = new JTextArea(3, 10);
    Vector<String> yankBuffer = new Vector<String>();
    JScrollPane scroller = new JScrollPane(history);   
    private JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);    
    LogoState state;

    void run(LogoLexer lexer) {
	
    Symbol parseResult;
	IRProgram program;
	LogoEvaluator eval = new LogoEvaluator();
	LogoParser parser = new LogoParser(lexer);
	
	try {
	    parseResult = parser.parse();
	    program = (IRProgram) parseResult.value;
	    program.visit(eval, state);
	} catch (LogoException le) {
	    System.out.println(le.getMessage());
	    return;
	} catch (Exception e) {
	    System.out.println("Fatal parse error: " + e.getMessage());
	    e.printStackTrace();
	}
    }
    
   

    void repl(String cmds) {
	StringInputStream is;

	is = new StringInputStream(cmds);
	LogoLexer lexer = new LogoLexer(is);
	run(lexer);
    
    }

    public void init()
    {
	JPanel panel = new JPanel();
	//JPanel textPanel = new JPanel(new BorderLayout());
	GridBagLayout gbl = new GridBagLayout();

	int [] widths = {20, 200}; // minimum column widths
	gbl.columnWidths = widths;

	JPanel textPanel = new JPanel(gbl);
	//textPanel.setSize(200, 200);

	text.addKeyListener(new MyKeyListener());
	text.setBackground(Color.cyan);
	//text.setText(PROMPT);
	text.setMinimumSize(new Dimension(300, 25));
	text.setPreferredSize(new Dimension(getWidth()-30, 50));
	text.setVisible(true);

	yankBuffer = new Vector<String>();
	history.setVisible(true);
	history.setEditable(false);
	/*
	  scroller.add(history);
	  scroller.setViewportView(history);*/
	
	scroller.setVerticalScrollBar(scroller.createVerticalScrollBar());
	scroller.setBorder(new EmptyBorder(0,0,0,0));
	scroller.setVisible(true);
	//textPanel.add(scroller, BorderLayout.NORTH);
	//textPanel.add(history, BorderLayout.NORTH);
	//textPanel.add(text, BorderLayout.CENTER);
	GridBagConstraints c = new GridBagConstraints();
	c.fill = GridBagConstraints.BOTH;
	c.gridx = 0;
	c.gridy = 0;
	c.weighty = 1.0;
	c.gridwidth = 2;
	gbl.setConstraints(scroller, c);
	textPanel.add(scroller);

	c = new GridBagConstraints();
	c.fill = GridBagConstraints.NONE;
	c.gridx = 0; c.gridy = 1;
	c.weightx = 0.0; c.weighty = 0.2;
	c.gridwidth = 1;
	c.anchor = GridBagConstraints.NORTH;
	JLabel prompt = new JLabel(PROMPT);
	prompt.setBackground(Color.cyan);
	gbl.setConstraints(prompt, c);
	textPanel.add(prompt);

	c = new GridBagConstraints();
	c.fill = GridBagConstraints.BOTH;
	c.gridx = 1;
	c.gridy = 1;
	c.weightx = 1.0; 
	c.gridwidth = 1;
	gbl.setConstraints(text, c);
	//textPanel.setPreferredSize(new Dimension(getWidth(), 100));
	textPanel.add(text);

	splitPane.setOneTouchExpandable(true);
	splitPane.setTopComponent(panel);
	splitPane.setBottomComponent(textPanel);
	//splitPane.setFont(new Font("Dialog", Font.PLAIN, 10));
	//splitPane.setDividerLocation(0.5);
	splitPane.setVisible(true);
	splitPane.setDividerLocation(400);

	state = new LogoState(); 
	panel.setSize(getWidth(), getWidth());
	panel.setBackground(Color.green);
	panel.setLayout(new GridLayout(1,1));
	panel.setVisible(true);
	panel.add(state.getTurtle().getDisplay());
	getContentPane().add(splitPane);	
	setVisible(true);
	state.getTurtle().getDisplay().rescale(getWidth(), getWidth());
	validate();
    }
    /*
    private AbstractAction enter = new AbstractAction()
    {
	public void actionPerformed(ActionEvent ae)	
	{
	    text.append("\n");
	}
    };
    */

    private class MyKeyListener implements KeyListener
    {
	boolean isYanking;	// true if last command was a yank
	int yankIndex;
	int yankStart = 0;
	int yankStop = 0;

	protected void yank() {
	    String t;
	    int p = text.getCaretPosition();
	    if (yankStop != p) {
		yankStart = p;
		isYanking = false;
	    }

	    if (isYanking) {
		if (yankIndex == yankBuffer.size())
		    t = "";
		else
		    t = (String) yankBuffer.elementAt(yankIndex);
		text.replaceRange(t, yankStart, yankStop);
	    } else {
		isYanking = true;
		t = (String) yankBuffer.elementAt(yankIndex);
		text.insert(t, yankStart);
	    }

	    yankStop = yankStart + t.length();
	}

	// insert command from previous position in command ring
	protected void yankPop() {
	    if (isYanking) {
		yankIndex = yankIndex - 1;
		if (yankIndex < 0)
		    yankIndex = yankBuffer.size() - 1;
	    } else {
		// make sure something is in command ring
		yankIndex = yankBuffer.size() - 1;
		if (yankIndex < 0) return;
	    }
	    yank();
	}

	// insert command from next position in command ring
	protected void yankPush() {
	    if (isYanking) {
		yankIndex = yankIndex + 1;
		if (yankIndex >= yankBuffer.size())
		    yankIndex = 0;
	    } else {
		// cannot push if command ring is empty
		return;
	    }
	    yank();
	}
	
	public void keyPressed(KeyEvent key)
	{
	    // Ctrl-ENTER sends an expression to the interpreter
	    if (key.getKeyCode() == KeyEvent.VK_ENTER && key.isControlDown()) {
		String t = text.getText();

		/*
		if (t.startsWith(PROMPT))
		    t = t.substring(PROMPT.length());
		*/

		t = t.trim();
		repl(t);
		repaint();
		history.append(t + "\n");
		yankBuffer.addElement(t);
		text.setText("");
	    }			  

// 	    if (key.getKeyCode() == KeyEvent.VK_ENTER && key.isControlDown())
// 	    {
// 		text.append("\n");
// 	    }     

	    if (key.getKeyCode() == KeyEvent.VK_P && key.isAltDown()) {
		yankPop();
	    }

	    if (key.getKeyCode() == KeyEvent.VK_N && key.isAltDown()) {
		yankPush();
	    }

	    if (key.getKeyCode() == KeyEvent.VK_UP) {
		yankPop();
	    }

	    if (key.getKeyCode() == KeyEvent.VK_DOWN) {
		yankPush();
	    }
	    
	    if (key.getKeyCode() == KeyEvent.VK_COPY && key.isControlDown())
	    {
		text.copy();
	    }			  

	    if (key.getKeyCode() == KeyEvent.VK_PASTE && key.isControlDown())
	    {
		text.paste();
	    }			

	    if (key.getKeyCode() == KeyEvent.VK_CUT && key.isControlDown())
	    {
		text.cut();
	    }			  
	}

	public void keyTyped(KeyEvent k)
	{}

	public void keyReleased(KeyEvent k)
	{}
	
    }

}
